home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pcmagazi / 1988 / 02 / paint.asm < prev    next >
Assembly Source File  |  1987-10-22  |  66KB  |  1,513 lines

  1. include paint.pub
  2. ;PAINT.COM for the IBM Personal Computer - 1987 by Jeff Prosise
  3.  
  4. bios_data     segment at 40h
  5.               org 1Ah
  6. buffer_head   dw ?                          ;pointer to keyboard buffer head
  7. buffer_tail   dw ?                          ;pointer to keyboard buffer tail
  8.               org 63h
  9. addr_6845     dw ?                          ;CRT Controller address
  10.               org 80h
  11. buffer_start  dw ?                          ;starting keyboard buffer address
  12. buffer_end    dw ?                          ;ending keyboard buffer address
  13. bios_data     ends
  14.  
  15. code          segment para public 'code'
  16.               assume cs:code
  17.               org 100h
  18. begin:        jmp main
  19.  
  20. copyright     db 'PAINT 1.0 (c) 1987 Ziff Communications Co.',13,10
  21.               db 'PC Magazine ',254,' Jeff Prosise',13,10,'$',1Ah
  22.  
  23. errmsg1       db 13,10,'File not found',13,10,'$'
  24. errmsg2       db 13,10,'Error reading file',13,10,'$'
  25. errmsg3       db 13,10,'Not enough memory',13,10,'$'
  26.  
  27. kbcode        db 10h                        ;get keystroke function code
  28. fileptr       dw 81h                        ;pointer to file name text
  29. data_segment  dw ?                          ;buffer segment
  30. doscolor      db ?                          ;screen color before execution
  31. insert_flag   db 0                          ;0=overwrite, 1=insert
  32. write_mode    db 0                          ;video insertion mode
  33. bufferptr     db 0                          ;pointer to current buffer page
  34. maxpage       db 0                          ;maximum page number
  35. mode          db 0                          ;0=color, 1=monochrome
  36. columns       db ?                          ;number of display columns -1
  37. lcolumns      dw ?                          ;number of display columns
  38. crtc_addr     dw ?                          ;CRT Controller base address
  39. blockxy       dw 0FFFFh                     ;first corner of block
  40. attribute     db 1Fh                        ;current paint attribute
  41. graphics      db 0                          ;current box character
  42. defchar       db ?                          ;default box character
  43. boxid         db ?                          ;box environment byte
  44. maskval       db 01010101b                  ;graphics mask value
  45. menu_attr     db 1Bh                        ;menu line attribute
  46. video_segment dw 0B800h                     ;video buffer segment
  47. delta         dw ?                          ;line length variable
  48. linelength    dw ?                          ;line length in bytes
  49. keyboard      label dword
  50. old9h         dw 2 dup (?)                  ;old interrupt 9h vector
  51.  
  52. quit_text     db 'Exit to DOS (Y/N)?',0
  53. save_text     db 'Save as: ',0
  54. box_text      db '1-',179,32,32,'2-',186,32,32,'3-',176,32,32,'4-',177,32,32
  55.               db '5-',178,32,32,'6-',219,32,32,'7-*',0
  56. fore_text     db 'Foreground:  0   1   2   3   4   5   6   7   8   9   '
  57.               db 'A   B   C   D   E   F',0
  58. back_text     db 'Back',0
  59. mono_text     db '1-Normal  2-Reverse  3-Bold  4-Underline',0
  60. block_text    db '1-Clear  2-Paint',0
  61. mode_text     db '1-Text Only  2-Text and Attributes',0
  62. help_text     db 'F1-Help  F2-Attribute  F3-Line  F4-Mode  F5-Block  '
  63.               db 'F6-Save  F7-Quit',0
  64.  
  65. key_table     db 81,73,65,64,63,62,61,60,59,160,157,155,152,145,116
  66.               db 115,141,83,82,79,71,80,77,75,72
  67. gr_table      db 17,81,145,98,96,144,162,34,160,130,66,129,80
  68.               db 5,69,84,21,68,85,25,38,10,40,138,168,42,136
  69.               db 170,137,70,152,100,6,9,24,36,102,153,65,20
  70. box_table     db 176,177,178,219,42
  71. mono_table    db 7,70h,0Fh,1
  72.  
  73. jump_table    dw offset up                  ;cursor-up key
  74.               dw offset left                ;cursor-left key
  75.               dw offset right               ;cursor-right key
  76.               dw offset down                ;cursor-down key
  77.               dw offset home                ;HOME key
  78.               dw offset endkey              ;END key
  79.               dw offset insert              ;INS key
  80.               dw offset delete              ;DEL key
  81.               dw offset up                  ;Ctrl-Up
  82.               dw offset left                ;Ctrl-Left
  83.               dw offset right               ;Ctrl-Right
  84.               dw offset down                ;Ctrl-Down
  85.               dw offset BoxUp               ;Alt-Up
  86.               dw offset BoxLeft             ;Alt-Left
  87.               dw offset BoxRight            ;Alt-Right
  88.               dw offset BoxDown             ;Alt-Down
  89.               dw offset help                ;F1
  90.               dw offset SelectAttr          ;F2
  91.               dw offset SelectBox           ;F3
  92.               dw offset SelectMode          ;F4
  93.               dw offset block               ;F5
  94.               dw offset save                ;F6
  95.               dw offset quit                ;F7
  96.               dw offset PgUp                ;PgUp
  97.               dw offset PgDn                ;PgDn
  98.  
  99. ;-----------------------------------------------------------------------------
  100. ;KBINT handles interrupt 9 and generates new extended keycodes.
  101. ;-----------------------------------------------------------------------------
  102. kbint         proc near
  103.               sti                           ;interrupts on
  104.               push ax                       ;save AX and BX
  105.               push bx
  106.               in al,60h                     ;read scan code
  107.               cmp al,72                     ;cursor up?
  108.               je checkctrl
  109.               cmp al,75                     ;cursor left?
  110.               je checkctrl
  111.               cmp al,77                     ;cursor right?
  112.               je checkctrl
  113.               cmp al,80                     ;cursor down?
  114.               je checkctrl
  115. oldint:       pop bx                        ;restore AX and BX
  116.               pop ax
  117.               jmp keyboard                  ;exit to BIOS handler
  118. ;
  119. ;Generate extended codes for Ctrl-Up, Down.
  120. ;
  121. checkctrl:    mov bl,al                     ;save scan code in BL
  122.               mov ah,2                      ;get shift key status
  123.               int 16h
  124.               test al,4                     ;Ctrl key pressed?
  125.               jz checkalt                   ;no, then check Alt key
  126.               cmp bl,75                     ;pass left or right key to BIOS
  127.               je oldint
  128.               cmp bl,77
  129.               je oldint
  130.               add bl,45h                    ;create new extended code
  131.               cmp bl,141
  132.               je process
  133.               mov bl,145
  134.               jmp short process             ;process it
  135. ;
  136. ;Generate extended codes for Alt-Up, Down, Left, and Right.
  137. ;
  138. checkalt:     test al,8                     ;Alt key pressed?
  139.               jz oldint                     ;no, then exit to BIOS
  140.               add bl,50h                    ;create new extended code
  141. ;
  142. ;Reset the keyboard and clear the interrupt.
  143. ;
  144. process:      in al,61h                     ;read control port value
  145.               mov ah,al                     ;save it in AH
  146.               or al,80h                     ;set the high bit
  147.               out 61h,al                    ;reset keyboard
  148.               mov al,ah                     ;retrieve original value
  149.               out 61h,al                    ;enable keyboard
  150.               cli
  151.               mov al,20h                    ;end the interrupt
  152.               out 20h,al
  153.               sti
  154. ;
  155. ;Insert the new keycode into the keyboard buffer.
  156. ;
  157.               mov ah,bl                     ;transfer code to AH
  158.               xor al,al                     ;zero AL
  159.               push dx                       ;save DX and DS
  160.               push ds
  161.               mov bx,bios_data              ;point DS to BIOS data area
  162.               mov ds,bx
  163.               assume ds:bios_data
  164.               cli                           ;interrupts off
  165.               mov bx,buffer_tail            ;get current tail address
  166.               mov dx,bx                     ;transfer it to DX
  167.               add dx,2                      ;advance to next position
  168.               cmp dx,buffer_end             ;wrap around if necessary
  169.               jne buffer
  170.               mov dx,buffer_start
  171. buffer:       cmp dx,buffer_head            ;is the buffer full?
  172.               je kbexit                     ;yes, then exit now
  173.               mov [bx],ax                   ;insert keycode into buffer
  174.               mov buffer_tail,dx            ;advance tail
  175. kbexit:       sti                           ;enable interrupts
  176.               pop ds                        ;restore registers
  177.               assume ds:nothing
  178.               pop dx
  179.               pop bx
  180.               pop ax
  181.               iret                          ;and exit
  182. kbint         endp
  183.  
  184. ;-----------------------------------------------------------------------------
  185. ;MAIN is the main procedure.
  186. ;-----------------------------------------------------------------------------
  187. main          proc near
  188.               assume cs:code,ds:code,es:code
  189. ;
  190. ;Request 64K of memory for buffer space.
  191. ;
  192.               mov ah,4Ah                    ;release memory beyond code seg
  193.               mov bx,4096
  194.               int 21h
  195.               mov ah,48h                    ;request 4000 paragraphs
  196.               mov bx,4000
  197.               int 21h
  198.               jnc save_seg                  ;continue if request granted
  199.               mov dx,offset errmsg3         ;abort if request denied
  200.               jmp short error_exit
  201. save_seg:     mov data_segment,ax           ;save data segment
  202. ;
  203. ;Parse the command line for a filename.
  204. ;
  205.               cld                           ;clear DF
  206.               mov si,81h                    ;point SI to command line
  207. parse1:       lodsb                         ;find first non-space
  208.               cmp al,32
  209.               je parse1
  210.               cmp al,13                     ;end-of-line?
  211.               jne filefound                 ;no, then it's a filename
  212.               mov byte ptr ds:[81h],0       ;place delimiter for no file
  213.               jmp short exbios              ;skip file load
  214. filefound:    dec si                        ;save starting text address
  215.               mov fileptr,si
  216.               mov bl,ds:[80h]               ;zero last byte in string
  217.               xor bh,bh
  218.               mov byte ptr ds:[bx+81h],0
  219. ;
  220. ;Open the file designated on the command line for input.
  221. ;
  222.               mov ax,3D00h                  ;request read-only access
  223.               mov dx,si                     ;point DS:DX to filespec
  224.               int 21h
  225.               jnc read_file                 ;branch if open succeeded
  226.               mov dx,offset errmsg1         ;print 'File not found'
  227. error_exit:   mov ah,9
  228.               int 21h
  229.               mov ax,4C01h                  ;terminate with error code
  230.               int 21h
  231. ;
  232. ;Read character/attribute data from the file.
  233. ;
  234. read_file:    mov bx,ax                     ;transfer file handle to BX
  235.               mov ah,3Fh                    ;read file data
  236.               mov cx,64000                  ;request 64,000 bytes
  237.               push ds                       ;point DS to data segment
  238.               mov ds,data_segment
  239.               assume ds:nothing
  240.               xor dx,dx                     ;point DX to beginning of segment
  241.               int 21h
  242.               pop ds                        ;restore DS
  243.               assume ds:code
  244.               jnc check_read                ;branch if no error occurred
  245.               mov dx,offset errmsg2         ;abort on read error
  246.               jmp short error_exit
  247. check_read:   or ax,ax                      ;abort if no bytes read
  248.               jne paginate
  249.               mov dx,offset errmsg2
  250.               jmp short error_exit
  251. paginate:     dec ax                        ;decrement count by 1
  252.               xor dx,dx                     ;determine number of pages
  253.               mov bx,4000
  254.               div bx
  255.               mov maxpage,al                ;save maximum page number
  256. close_file:   mov ah,3Eh                    ;close file
  257.               int 21h
  258. ;
  259. ;Determine whether or not the BIOS supports extended keyboard functions.
  260. ;
  261. exbios:       mov ah,5                      ;write FFFFh to keyboard buffer
  262.               mov cx,0FFFFh
  263.               int 16h
  264.               mov ah,10h                    ;then read it back
  265.               int 16h
  266.               cmp ax,0FFFFh                 ;is AX set correctly?
  267.               je video                      ;yes, then don't reset INT 9
  268. ;
  269. ;Point the interrupt 9 vector to the internal keyboard handler.
  270. ;
  271.               mov kbcode,0                  ;modify KBCODE for old BIOS
  272.               push es
  273.               assume es:nothing
  274.               mov ax,3509h                  ;get current vector
  275.               int 21h
  276.               mov old9h,bx                  ;save it
  277.               mov old9h[2],es
  278.               mov ax,2509h                  ;then reset it
  279.               mov dx,offset kbint
  280.               int 21h
  281.               pop es
  282.               assume es:code
  283. ;
  284. ;Determine whether video is color or monochrome.
  285. ;
  286. video:        push ds                       ;get address of CRT Controller
  287.               mov ax,bios_data
  288.               mov ds,ax
  289.               assume ds:bios_data
  290.               mov ax,addr_6845
  291.               mov crtc_addr,ax              ;save it
  292.               pop ds
  293.               assume ds:code
  294.               test ax,40h                   ;is bit 6 of CRTC address set?
  295.               jnz more_video                ;yes, then it's a color adapter
  296.               inc mode                      ;no, then it's monochrome
  297.               mov video_segment,0B000h      ;modify attributes for monochrome
  298.               mov attribute,7
  299.               mov menu_attr,7
  300. ;
  301. ;Determine number of display columns, screen color, and video page number.
  302. ;
  303. more_video:   mov ah,15                     ;get number of columns and page
  304.               int 10h
  305.               mov al,ah
  306.               xor ah,ah
  307.               mov lcolumns,ax               ;store number of columns
  308.               mov linelength,ax             ;store line length in bytes
  309.               shl linelength,1
  310.               dec al                        ;store number of columns - 1
  311.               mov columns,al
  312.               mov cl,79                     ;determine number of bytes
  313.               sub cl,al                     ;  from end of one line to
  314.               shl cl,1                      ;  beginning of next
  315.               xor ch,ch
  316.               mov delta,cx
  317.               cmp al,79                     ;adjust if more than 80 columns
  318.               jna no_adjust                 ;  are currently displayed
  319.               mov columns,79
  320.               mov lcolumns,80
  321.               mov delta,0
  322. no_adjust:    mov ah,8                      ;read current attribute
  323.               int 10h
  324.               mov doscolor,ah               ;store it for use upon exit
  325.               or bh,bh                      ;make sure page zero is active
  326.               je clrscr
  327.               mov ax,0500h                  ;activate it if it's not
  328.               int 10h
  329. ;
  330. ;Clear the screen or write data read from screen file to video memory.
  331. ;
  332. clrscr:       cmp byte ptr ds:[81h],0       ;was a data file read?
  333.               jne show_file                 ;yes, then display contents
  334.               mov bh,attribute              ;no, then clear the screen
  335.               call ClearScreen
  336.               jmp short getkey              ;leave starting screen blank
  337. show_file:    call ShowFile
  338. ;
  339. ;Solicit keystrokes and process non-extended keycodes.
  340. ;
  341. getkey:       call ReadKey                  ;get a keystroke
  342.               or al,al                      ;branch on entry of extended code
  343.               je excode
  344.               cmp al,0E0h
  345.               je excode
  346.               cmp al,8                      ;BACKSPACE key?
  347.               jne enter
  348.               or dl,dl                      ;currently at left edge of screen?
  349.               je getkey                     ;yes, then ignore it
  350.               call backspace                ;delete last character
  351.               jmp short getkey              ;return for more
  352. enter:        cmp al,13                     ;ENTER key?
  353.               jne escape
  354.               mov ah,2                      ;advance cursor to next line
  355.               xor bh,bh
  356.               inc dh
  357.               cmp dh,25                     ;wrap around if necessary
  358.               jne nowrap
  359.               xor dh,dh
  360. nowrap:       xor dl,dl
  361.               int 10h
  362.               jmp short getkey              ;return for more
  363. escape:       cmp al,27                     ;ESC key?
  364.               jne charkey
  365.               mov blockxy,0FFFFh            ;reset block indicator
  366.               jmp short getkey              ;return for more
  367. charkey:      cmp al,32                     ;character key?
  368.               jb getkey                     ;no, then ignore it
  369.               call WriteChar                ;yes, then process it
  370.               jmp short getkey              ;return for more
  371. ;
  372. ;Process an extended keycode.
  373. ;
  374. excode:       mov al,ah                     ;transfer keycode to AL
  375.               mov di,offset key_table       ;point DI to keycode table
  376.               mov cx,25                     ;25 keycodes to check
  377.               repne scasb                   ;scan table for current keycode
  378.               jne getkey                    ;return if keycode not found
  379.               mov bx,cx                     ;move index to BX
  380. pcall:        shl bx,1                           ;double it
  381.               call cs:[offset jump_table+bx]     ;call handling routine
  382.               mov ah,3                           ;get cursor position
  383.               xor bh,bh
  384.               int 10h
  385.               jmp short getkey                   ;return for more
  386. main          endp
  387.  
  388. ;-----------------------------------------------------------------------------
  389. ;ShowFile displays a 4000-byte block indexed by DATA_SEGMENT and BUFFERPTR.
  390. ;-----------------------------------------------------------------------------
  391. ShowFile      proc near
  392.               mov ax,4000                   ;find starting buffer address
  393.               mov bl,bufferptr
  394.               xor bh,bh
  395.               mul bx
  396.               mov si,ax                     ;transfer it to SI
  397.               push ds                       ;point DS to data segment
  398.               assume ds:nothing
  399.               mov ds,data_segment
  400.               xor dx,dx                     ;set DX for home cursor position
  401.               mov cx,25                     ;25 display lines
  402. show1:        push cx
  403.               mov cx,lcolumns               ;number of display columns
  404. show2:        push cx
  405.               mov ah,2                      ;position the cursor
  406.               int 10h
  407.               lodsw                         ;get one C/A pair
  408.               mov bl,ah                     ;transfer attribute to BL
  409.               mov ah,9                      ;display character and attribute
  410.               mov cx,1
  411.               int 10h
  412.               inc dl                        ;advance cursor
  413.               pop cx
  414.               loop show2                    ;loop until this line is done
  415.               inc dh                        ;home cursor to start of next line
  416.               xor dl,dl
  417.               add si,delta                  ;adjust SI for other than 80 cols
  418.               pop cx
  419.               loop show1                    ;loop until 25 lines are done
  420.               pop ds                        ;restore DS
  421.               assume ds:code
  422.               mov ah,2                      ;home the cursor
  423.               xor dx,dx
  424.               int 10h
  425.               ret                           ;and exit
  426. ShowFile      endp
  427.  
  428. ;-----------------------------------------------------------------------------
  429. ;ReadKey reads a keypress.
  430. ;Exit:  AX - keycode
  431. ;-----------------------------------------------------------------------------
  432. ReadKey       proc near
  433.               mov ah,kbcode                 ;get function code
  434.               inc ah
  435.               int 16h                       ;check buffer status
  436.               jnz read                      ;branch if a keycode is ready
  437.               int 28h                       ;generate interrupt 28h
  438.               jmp short ReadKey             ;enter polling loop again
  439. read:         mov ah,kbcode                 ;read key
  440.               int 16h
  441.               ret                           ;and exit
  442. ReadKey       endp
  443.  
  444. ;-----------------------------------------------------------------------------
  445. ;ClearScreen clears the 25-line viewing area and homes the cursor.
  446. ;Entry:  BH - attribute
  447. ;-----------------------------------------------------------------------------
  448. ClearScreen   proc near
  449.               mov ax,0600h                  ;clear screen with function 6
  450.               xor cx,cx
  451.               mov dh,24
  452.               mov dl,columns
  453.               int 10h
  454.               mov ah,2                      ;home the cursor
  455.               xor dx,dx
  456.               xor bh,bh
  457.               int 10h
  458.               ret
  459. ClearScreen   endp
  460.  
  461. ;-----------------------------------------------------------------------------
  462. ;HELP presents a help line denoting function key assignments.
  463. ;-----------------------------------------------------------------------------
  464. help          proc near
  465.               mov si,offset help_text       ;display help text
  466.               call MenuLine
  467. help1:        call readkey                  ;wait for a keypress
  468.               call RestoreLine              ;erase the help line
  469.               ret
  470. help          endp
  471.  
  472. ;-----------------------------------------------------------------------------
  473. ;QUIT exits the application.
  474. ;-----------------------------------------------------------------------------
  475. quit          proc near
  476.               mov si,offset quit_text       ;display menu line
  477.               call MenuLine   
  478. quit1:        call ReadKey                  ;get a keypress
  479.               and al,0DFh                   ;capitalize response
  480.               cmp al,'Y'                    ;was the response 'Yes?'
  481.               je quit2                      ;yes, then exit
  482.               cmp al,'N'                    ;was the response 'No?'
  483.               je quit4                      ;yes, then return to application
  484.               cmp al,27                     ;ESC key?
  485.               je quit4                      ;yes, then return to application
  486.               jmp short quit1               ;get another keypress
  487. quit2:        mov bh,doscolor               ;clear screen before exit
  488.               call ClearScreen
  489.               mov ah,1                      ;restore the cursor
  490.               mov cx,cursor_mode
  491.               int 10h
  492.               cmp kbcode,10h                ;skip ahead if extended BIOS
  493.               je quit3
  494.               xor ax,ax                     ;restore the interrupt 9 vector
  495.               mov es,ax
  496.               cli
  497.               mov ax,old9h
  498.               mov es:[24h],ax
  499.               mov ax,old9h[2]
  500.               mov es:[26h],ax
  501.               sti
  502. quit3:        add sp,4                      ;clean up the stack
  503.               mov ah,9
  504.               mov dx,offset copyright
  505.               int 21h
  506.               mov ax,4C00h                  ;terminate
  507.               int 21h
  508. quit4:        call RestoreLine              ;restore menu line
  509.               ret                           ;return to application
  510. quit          endp
  511.  
  512. ;-----------------------------------------------------------------------------
  513. ;SAVE saves the current screen to disk.
  514. ;-----------------------------------------------------------------------------
  515. save          proc near
  516.               mov si,offset save_text       ;display menu line
  517.               call MenuLine
  518.               mov ah,1                      ;display cursor
  519.               mov cx,cursor_mode
  520.               int 10h
  521. getname:      mov si,fileptr                ;read filespec from keyboard
  522.               mov di,si
  523.               mov cl,70
  524.               mov dx,1809h
  525.               call ReadString
  526.               or cl,cl                      ;stop if nothing was entered
  527.               jne save_file
  528.               call RestoreLine
  529.               ret
  530. save_file:    mov ah,3Ch                    ;open the file for writing
  531.               xor cx,cx
  532.               mov dx,fileptr
  533.               int 21h
  534.               jc save_error                 ;jump on error
  535.               push ax                       ;save file handle
  536.               call RestoreLine              ;restore menu line
  537.               mov ah,3                      ;read and save cursor position
  538.               xor bh,bh
  539.               int 10h
  540.               push dx
  541.               call PutVideo                 ;copy video to data buffer
  542.               mov ah,2                      ;reset cursor
  543.               pop dx
  544.               int 10h
  545.               mov ax,4000                   ;write data to disk
  546.               mov bl,maxpage
  547.               inc bl
  548.               xor bh,bh
  549.               mul bx
  550.               mov cx,ax
  551.               mov ah,40h
  552.               pop bx
  553.               push ds
  554.               mov ds,data_segment
  555.               assume ds:nothing
  556.               xor dx,dx
  557.               int 21h
  558.               pop ds
  559.               assume ds:code
  560.               mov ah,3Eh                    ;close the file
  561.               int 21h
  562.               ret
  563. ;
  564. ;An error was encountered opening the file.  Resolicit the filespec.
  565. ;
  566. save_error:   mov ax,0E07h                  ;beep
  567.               int 10h
  568.               mov ah,2                      ;reset cursor
  569.               mov dx,1809h
  570.               xor bh,bh
  571.               int 10h
  572.               jmp getname                   ;solicit filespec again
  573. save          endp
  574.  
  575. ;-----------------------------------------------------------------------------
  576. ;PutVideo writes the current video page to the data buffer.
  577. ;-----------------------------------------------------------------------------
  578. PutVideo      proc near
  579.               push es                       ;point ES:DI to buffer
  580.               mov es,data_segment
  581.               assume es:nothing
  582.               mov ax,4000
  583.               mov bl,bufferptr
  584.               xor bh,bh
  585.               mul bx
  586.               mov di,ax
  587.               xor dx,dx
  588.               mov cx,25                     ;copy contents a line at a time
  589. put2:         push cx 
  590.               mov cx,lcolumns
  591. put3:         mov ah,2
  592.               int 10h
  593.               mov ah,8
  594.               int 10h
  595.               stosw
  596.               inc dl
  597.               loop put3
  598.               add di,delta                  ;adjust for other than 80 columns
  599.               inc dh
  600.               xor dl,dl
  601.               pop cx
  602.               loop put2
  603.               pop es                        ;restore ES and exit
  604.               assume es:code
  605.               ret
  606. PutVideo      endp
  607.  
  608. ;-----------------------------------------------------------------------------
  609. ;BLOCK function allows screen regions to be cleared or painted.
  610. ;-----------------------------------------------------------------------------
  611. bwidth        db ?                          ;block width in columns
  612. firstcol      db ?                          ;starting column number of block
  613. c_loc         dw ?                          ;cursor position
  614.  
  615. block         proc near
  616.               cmp blockxy,0FFFFh            ;first corner?
  617.               jne block1                    ;no, then branch
  618.               mov blockxy,dx                ;yes, then save cursor position
  619.               ret                           ;and exit
  620. block1:       mov cx,blockxy                ;retrieve opposite corner location
  621.               cmp cx,dx                     ;are CX and DX the same?
  622.               jne notfull                   ;no, then branch
  623.               xor cx,cx                     ;yes, then indicate full screen
  624.               mov dh,24
  625.               mov dl,columns
  626.               jmp short block3
  627. notfull:      cmp cl,dl                     ;swap if necessary
  628.               jbe block2
  629.               xchg cl,dl
  630. block2:       cmp ch,dh
  631.               jbe block3
  632.               xchg ch,dh
  633. block3:       push cx                       ;save block parameters
  634.               push dx
  635.               mov si,offset block_text      ;display menu line
  636.               call MenuLine
  637. ;
  638. ;Block corners are recorded.  Get menu option and act accordingly.
  639. ;
  640. block4:       call ReadKey                  ;get response
  641.               cmp al,27                     ;ESC key?
  642.               jne block5
  643.               mov blockxy,0FFFFh            ;reset block definition
  644.               call RestoreLine              ;restore menu line
  645.               pop dx                        ;clean up the stack and exit
  646.               pop cx
  647.               ret
  648. ;
  649. ;Clear the indicated region if menu option '1' was selected.
  650. ;
  651. block5:       cmp al,'1'                    ;clear region?
  652.               jne block6
  653.               call RestoreLine              ;restore last line
  654.               pop dx                        ;retrieve block corrdinates
  655.               pop cx
  656.               mov ax,0600h                  ;yes, then clear contents
  657.               mov bh,attribute
  658.               int 10h
  659.               mov blockxy,0FFFFh            ;reset block function
  660.               ret
  661. ;
  662. ;Paint the indicated region if menu option '2' was selected.
  663. ;
  664. block6:       cmp al,'2'                    ;paint region?
  665.               jne block4
  666.               call RestoreLine              ;restore menu line
  667.               mov ah,3                      ;get cursor position
  668.               xor bh,bh
  669.               int 10h
  670.               mov c_loc,dx                  ;save it
  671.               pop cx                        ;retrieve and swap parameters
  672.               pop dx
  673.               mov firstcol,dl               ;save starting column number
  674.               sub cl,dl                     ;determine block width
  675.               inc cl
  676.               mov bwidth,cl
  677.               sub ch,dh                     ;then block height
  678.               inc ch
  679.               mov cl,ch
  680.               xor ch,ch
  681. block7:       push cx                       ;scan region and set attributes
  682.               mov cl,bwidth
  683.               xor ch,ch
  684. block8:       push cx
  685.               mov ah,2                      ;position cursor
  686.               int 10h
  687.               call SetAttribute             ;set current attribute
  688.               inc dl                        ;advance to next column
  689.               pop cx
  690.               loop block8                   ;loop until this line is complete
  691.               inc dh                        ;advance to next row
  692.               mov dl,firstcol
  693.               pop cx
  694.               loop block7                   ;loop until all lines are done
  695.               mov ah,2                      ;restore cursor position
  696.               mov dx,c_loc
  697.               int 10h
  698.               mov blockxy,0FFFFh            ;reset block function
  699.               ret
  700. block         endp
  701.  
  702. ;-----------------------------------------------------------------------------
  703. ;Box routines process presses of Alt-Up, Down, Right, and Left.
  704. ;-----------------------------------------------------------------------------
  705. BoxUp         proc near
  706.               or dh,dh                      ;top line?
  707.               je boxup1                     ;yes, then ignore keypress
  708.               mov al,7                      ;generate default code
  709.               mul graphics
  710.               add al,179
  711.               mov bx,dx                     ;define next cursor location
  712.               dec bh
  713.               mov boxid,16                  ;bias box code
  714.               call DrawChars                ;draw box characters
  715. boxup1:       ret
  716. BoxUp         endp
  717.  
  718. BoxDown       proc near
  719.               cmp dh,24                     ;bottom line?
  720.               je boxdn1                     ;yes, then ignore keypress
  721.               mov al,7                      ;generate default code
  722.               mul graphics
  723.               add al,179
  724.               mov bx,dx                     ;define next cursor location
  725.               inc bh
  726.               mov boxid,1                   ;bias box code
  727.               call DrawChars                ;draw box characters
  728. boxdn1:       ret
  729. BoxDown       endp
  730.  
  731. BoxLeft       proc near
  732.               or dl,dl                      ;left edge of screen?
  733.               je boxlf1                     ;yes, then ignore keypress
  734.               mov al,9                      ;generate default code
  735.               mul graphics
  736.               add al,196
  737.               mov bx,dx                     ;define next cursor location
  738.               dec bl
  739.               mov boxid,4                   ;bias box code
  740.               call DrawChars                ;draw box characters
  741. boxlf1:       ret
  742. BoxLeft       endp
  743.  
  744. BoxRight      proc near
  745.               cmp dl,columns                ;right edge of screen?
  746.               je boxrt1                     ;yes, then ignore keypress
  747.               mov al,9                      ;generate default code
  748.               mul graphics
  749.               add al,196
  750.               mov bx,dx                     ;define next cursor location
  751.               inc bl
  752.               mov boxid,64                  ;bias box code
  753.               call DrawChars                ;draw box characters
  754. boxrt1:       ret
  755. BoxRight      endp
  756.  
  757. ;-----------------------------------------------------------------------------
  758. ;DrawChars is called by the directional box routines to draw box characters.
  759. ;Entry:  AL - default box character
  760. ;        BX - next cursor position
  761. ;-----------------------------------------------------------------------------
  762. DrawChars     proc near
  763.               mov defchar,al                ;store default code
  764.               push bx                       ;save next cursor location
  765.               cmp graphics,0                ;adjust BOXID if double line
  766.               je drawc1
  767.               shl boxid,1
  768. drawc1:       call DrawBox                  ;draw character in current cell
  769.               mov ah,2                      ;move cursor
  770.               pop dx
  771.               xor bh,bh
  772.               int 10h
  773.               mov boxid,0                   ;reset box code
  774.               call DrawBox                  ;draw next box character
  775.               ret
  776. DrawChars     endp
  777.  
  778. ;-----------------------------------------------------------------------------
  779. ;DrawBox draws the appropriate box character at the current cursor position.
  780. ;-----------------------------------------------------------------------------
  781. DrawBox       proc near
  782.               cmp graphics,1                ;branch if line drawing characters
  783.               jna db1                       ;  are selected
  784.               mov al,graphics               ;form character code
  785.               sub al,2
  786.               mov bx,offset box_table
  787.               xlat box_table
  788.               jmp short db3                 ;display character and exit
  789. db1:          call GetEnv                   ;determine character code
  790.               mov al,boxid                  ;transfer to AL
  791.               mov cl,4                      ;generate desired character code
  792.               rol al,cl
  793.               mov cx,40                     ;see if character exists
  794.               mov di,offset gr_table
  795.               repne scasb
  796.               je db2                        ;display it if it does
  797.               and al,maskval                ;mask mixed characters
  798.               mov cx,40                     ;search again
  799.               mov di,offset gr_table
  800.               repne scasb
  801.               je db2
  802.               mov al,defchar                ;default to line character
  803.               jmp short db3
  804. db2:          mov al,218                    ;print the character
  805.               sub al,cl
  806. db3:          call DisplayChar
  807.               ret
  808. DrawBox       endp
  809.  
  810. ;-----------------------------------------------------------------------------
  811. ;SelectMode lets the user specify whether attributes will be inserted
  812. ;along with typed text.
  813. ;-----------------------------------------------------------------------------
  814. SelectMode    proc near
  815.               mov si,offset mode_text       ;display menu line
  816.               call MenuLine
  817. sm1:          call ReadKey                  ;get response
  818.               cmp al,27                     ;check for ESC key
  819.               je sm2
  820.               cmp al,'1'                    ;reject invalid entries
  821.               jb sm1
  822.               cmp al,'2'
  823.               ja sm1
  824.               sub al,'1'                    ;normalize entry
  825.               mov write_mode,al             ;save it
  826. sm2:          call Restoreline              ;close and exit
  827.               ret
  828. SelectMode    endp
  829.  
  830. ;-----------------------------------------------------------------------------
  831. ;SelectBox pops up the box character selection menu.
  832. ;-----------------------------------------------------------------------------
  833. SelectBox     proc near
  834.               mov si,offset box_text        ;display menu line
  835.               call MenuLine
  836. sb1:          call ReadKey                  ;get response
  837.               cmp al,27                     ;ESC key?
  838.               je sb3                        ;yes, then exit
  839.               cmp al,13                     ;ENTER?
  840.               je sb3                        ;yes, then exit
  841.               cmp al,'1'                    ;reject invalid responses
  842.               jb sb1
  843.               cmp al,'7'
  844.               ja sb1
  845.               sub al,'1'                    ;normalize entry
  846.               mov graphics,al               ;then store it
  847.               or al,al                      ;set mask value
  848.               jne sb2
  849.               mov maskval,01010101b
  850.               jmp short sb3
  851. sb2:          cmp al,1
  852.               jne sb3
  853.               mov maskval,10101010b
  854. sb3:          call RestoreLine              ;restore menu line
  855.               ret
  856. SelectBox     endp
  857.  
  858. ;-----------------------------------------------------------------------------
  859. ;SelectAttr pops up the screen attribute selection menu.
  860. ;-----------------------------------------------------------------------------
  861. tmpcol        db ?                          ;attribute under cursor
  862.  
  863. SelectAttr    proc near
  864.               mov ah,8                      ;get attribute under cursor
  865.               xor bh,bh
  866.               int 10h
  867.               mov tmpcol,ah                 ;save it
  868.               cmp mode,0                    ;color video?
  869.               je sa0                        ;yes, then branch
  870. ;
  871. ;Display attribute menu for monochrome systems.
  872. ;
  873.               mov si,offset mono_text       ;display menu line
  874.               call MenuLine
  875. mono1:        call ReadKey                  ;get response
  876.               or al,al                      ;function key F2?
  877.               jne mono2
  878.               cmp ah,60
  879.               jne mono1
  880.               mov ah,tmpcol                 ;use attribute under cursor
  881.               mov attribute,ah
  882.               jmp short mono3               ;exit
  883. mono2:        cmp al,27                     ;exit if ESC was pressed
  884.               je mono3
  885.               cmp al,'1'                    ;reject invalid responses
  886.               jb mono1
  887.               cmp al,'4'
  888.               ja mono1
  889.               sub al,'1'                    ;normalize entry
  890.               mov bx,offset mono_table      ;determine new attribute
  891.               xlat mono_table
  892.               mov attribute,al              ;save it
  893. mono3:        call RestoreLine              ;restore line and exit
  894.               ret
  895. ;
  896. ;Display attribute menu for color systems.
  897. ;
  898. sa0:          mov si,offset fore_text       ;display menu line
  899.               call MenuLine
  900.               mov dx,180Eh                  ;display colors
  901.               xor bx,bx
  902. sa1:          mov ah,2
  903.               int 10h
  904.               mov ax,09DBh
  905.               mov cx,2
  906.               int 10h
  907.               add dl,4
  908.               inc bl
  909.               test bl,10h
  910.               jz sa1
  911. sa2:          call ReadKey                  ;get foreground color response
  912.               or al,al                      ;function key F2?
  913.               jne notf1
  914.               cmp ah,60
  915.               jne sa2
  916.               mov ah,tmpcol                 ;use attribute under cursor
  917.               mov attribute,ah
  918.               jmp short endselect           ;and exit
  919. notf1:        cmp al,13                     ;ENTER key?
  920.               je sa4
  921.               cmp al,27                     ;ESC?
  922.               je endselect
  923.               cmp al,'0'                    ;reject invalid responses
  924.               jb sa2
  925.               cmp al,'9'
  926.               jna sa3
  927.               and al,0DFh                   ;normalize entry
  928.               cmp al,'A'
  929.               jb sa2
  930.               cmp al,'F'
  931.               ja sa2
  932.               sub al,7
  933. sa3:          sub al,30h
  934.               and attribute,0F0h            ;modify foreground color
  935.               or attribute,al
  936. sa4:          mov si,offset back_text       ;display background colors
  937.               mov dx,1800h
  938.               mov bl,menu_attr
  939.               call WriteLine
  940.               mov ah,2
  941.               mov dx,182Ch
  942.               int 10h
  943.               mov ax,0920h
  944.               mov cx,34
  945.               int 10h
  946. sa5:          call ReadKey                  ;get background color response
  947.               cmp al,13
  948.               je endselect
  949.               cmp al,27
  950.               je endselect
  951.               cmp al,'0'
  952.               jb sa4
  953.               cmp al,'7'
  954.               ja sa4
  955.               sub al,30h
  956.               mov cl,4
  957.               shl al,cl
  958.               and attribute,0Fh             ;modify background color
  959.               or attribute,al
  960. endselect:    call RestoreLine              ;restore menu line
  961.               ret
  962. SelectAttr    endp
  963.  
  964. ;-----------------------------------------------------------------------------
  965. ;WriteChar processes a press of a character key.
  966. ;-----------------------------------------------------------------------------
  967. WriteChar     proc near
  968.               cmp insert_flag,0             ;insert state on?
  969.               je disp_char                  ;no, then skip insert sequence
  970.               mov cl,columns                ;calculate number of shifts
  971.               sub cl,dl
  972.               xor ch,ch
  973.               jcxz disp_char
  974.               push ax                       ;save character and position
  975.               push dx
  976.               call VideoAddr                ;calculate video address
  977.               mov bx,cx                     ;determine starting address
  978.               shl bx,1
  979.               add si,bx
  980.               mov di,si
  981.               sub si,2
  982.               push ds                       ;save DS and ES
  983.               push es
  984.               assume ds:nothing,es:nothing
  985.               mov ds,video_segment
  986.               mov es,video_segment
  987.               std                           ;set DF temporarily
  988.               mov dx,crtc_addr              ;get CRT Controller address
  989.               add dx,6                      ;address status register
  990. vwait:        in al,dx                      ;wait for vertical retrace
  991.               test al,8
  992.               jz vwait
  993.               cmp write_mode,0              ;push text and attributes?
  994.               jne push_all                  ;yes, then branch
  995. write_loop:   movsb                         ;shift text only
  996.               dec si
  997.               dec di
  998.               loop write_loop
  999.               jmp short shift_done
  1000. push_all:     rep movsw                     ;shift text and attributes
  1001. shift_done:   cld                           ;restore DF
  1002.               pop es                        ;restore DS and ES
  1003.               pop ds
  1004.               assume ds:code,es:code
  1005.               pop dx                        ;retrieve character and position
  1006.               pop ax
  1007. disp_char:    call DisplayChar              ;display the character
  1008.               mov ah,2                      ;advance the cursor
  1009.               cmp dl,columns                ;prevent overrun
  1010.               je nomove
  1011.               inc dl
  1012. nomove:       int 10h
  1013.               ret
  1014. WriteChar     endp
  1015.  
  1016. ;-----------------------------------------------------------------------------
  1017. ;VideoAddr calculates the page zero video buffer address that corresponds
  1018. ;to the cursor coordinates held in DX.
  1019. ;Entry:  DH,DL - cursor row and column | Exit:  SI - buffer offset
  1020. ;-----------------------------------------------------------------------------
  1021. VideoAddr     proc near
  1022.               mov ax,linelength             ;row * 160
  1023.               mul dh
  1024.               shl dl,1                      ;add column * 2
  1025.               xor dh,dh
  1026.               add ax,dx
  1027.               mov si,ax                     ;transfer to SI
  1028.               ret
  1029. VideoAddr     endp
  1030.  
  1031. ;-----------------------------------------------------------------------------
  1032. ;INSERT processes a press of the INS key.
  1033. ;-----------------------------------------------------------------------------
  1034. insert        proc near
  1035.               xor insert_flag,1             ;toggle flag
  1036.               ret
  1037. insert        endp
  1038.  
  1039. ;-----------------------------------------------------------------------------
  1040. ;UP processes a press of Cursor-Up  or Ctrl-Up.
  1041. ;-----------------------------------------------------------------------------
  1042. up            proc near
  1043.               or dh,dh                      ;currently on top row?
  1044.               je done                       ;yes, then ignore the keypress
  1045.               push ax                       ;save keycode
  1046.               cmp al,100                    ;paint cell if Ctrl is pressed
  1047.               jb up1
  1048.               call SetAttribute
  1049. up1:          dec dh                        ;move cursor up a row
  1050. set_cursor:   mov ah,2
  1051.               xor bh,bh
  1052.               int 10h
  1053.               pop ax                        ;retrieve keycode
  1054.               cmp al,100                    ;paint cell if Ctrl is pressed
  1055.               jb done
  1056.               call SetAttribute
  1057. done:         ret
  1058. up            endp
  1059.  
  1060. ;-----------------------------------------------------------------------------
  1061. ;LEFT processes a press of Cursor-Left or Ctrl-Left.
  1062. ;-----------------------------------------------------------------------------
  1063. left          proc near
  1064.               or dl,dl                      ;currently at left edge?
  1065.               je done                       ;yes, then ignore the keypress
  1066.               push ax                       ;save keycode
  1067.               cmp al,100                    ;paint cell if Ctrl is pressed
  1068.               jb lf1
  1069.               call SetAttribute
  1070. lf1:          dec dl                        ;move cursor left one column
  1071.               jmp short set_cursor
  1072. left          endp
  1073.  
  1074. ;-----------------------------------------------------------------------------
  1075. ;RIGHT processes a press of Cursor-Right or Ctrl-Right.
  1076. ;-----------------------------------------------------------------------------
  1077. right         proc near
  1078.               cmp dl,columns                ;currently at right border?
  1079.               je done                       ;yes, then ignore the keypress
  1080.               push ax                       ;save keycode
  1081.               cmp al,100                    ;paint cell if Ctrl is pressed
  1082.               jb rt1
  1083.               call SetAttribute
  1084. rt1:          inc dl                        ;move cursor right one column
  1085.               jmp short set_cursor
  1086. right         endp
  1087.  
  1088. ;-----------------------------------------------------------------------------
  1089. ;DOWN processes a press of Cursor-Down or Ctrl-Down.
  1090. ;-----------------------------------------------------------------------------
  1091. down          proc near
  1092.               cmp dh,24                     ;currently on bottom row?
  1093.               je done                       ;yes, then ignore the keypress
  1094.               push ax                       ;save keycode
  1095.               cmp al,100                    ;paint cell if Ctrl is pressed
  1096.               jb dn1
  1097.               call SetAttribute
  1098. dn1:          inc dh                        ;move cursor down a row
  1099.               jmp short set_cursor
  1100. down          endp
  1101.  
  1102. ;-----------------------------------------------------------------------------
  1103. ;HOME processes a press of the HOME key.
  1104. ;-----------------------------------------------------------------------------
  1105. home          proc near
  1106.               xor dl,dl                     ;set cursor to start of line
  1107. home1:        mov ah,2
  1108.               xor bh,bh
  1109.               int 10h
  1110.               ret
  1111. home          endp
  1112.  
  1113. ;-----------------------------------------------------------------------------
  1114. ;ENDKEY processes a press of the END key.
  1115. ;-----------------------------------------------------------------------------
  1116. endkey        proc near
  1117.               mov dl,columns                ;set cursor to end of line
  1118.               jmp home1
  1119. endkey        endp
  1120.  
  1121. ;-----------------------------------------------------------------------------
  1122. ;PgUp and PgDn routines flip to the last/next page in the buffer.
  1123. ;-----------------------------------------------------------------------------
  1124. PgUp          proc near
  1125.               cmp maxpage,0                 ;ignore if there's only one page
  1126.               je nopress
  1127.               call PutVideo                 ;write current page to buffer
  1128.               dec bufferptr                 ;go back one page
  1129.               test bufferptr,80h            ;wrap around if necessary
  1130.               jz pg1
  1131.               mov al,maxpage
  1132.               mov bufferptr,al
  1133. pg1:          call ShowFile                 ;display new page
  1134. nopress:      ret                           ;exit
  1135. PgUp          endp
  1136.  
  1137. PgDn          proc near
  1138.               cmp maxpage,0                 ;ignore if there's only one page
  1139.               je nopress
  1140.               call PutVideo
  1141.               inc bufferptr                 ;advance page pointer
  1142.               mov al,maxpage                ;wrap if necessary
  1143.               cmp al,bufferptr
  1144.               jae pg1
  1145.               mov bufferptr,0
  1146.               jmp short pg1
  1147. PgDn          endp
  1148.  
  1149. ;-----------------------------------------------------------------------------
  1150. ;DisplayChar writes the character in AL to the current cursor position.
  1151. ;-----------------------------------------------------------------------------
  1152. DisplayChar   proc near
  1153.               mov ah,9
  1154.               cmp write_mode,0              ;write attribute also?
  1155.               jne dc1
  1156.               inc ah                        ;no, then change function number
  1157. dc1:          xor bh,bh
  1158.               mov bl,attribute
  1159.               mov cx,1
  1160.               int 10h
  1161.               ret
  1162. DisplayChar   endp
  1163.  
  1164. ;-----------------------------------------------------------------------------
  1165. ;SetAttribute sets the attribute of the character under the cursor.
  1166. ;-----------------------------------------------------------------------------
  1167. SetAttribute  proc near
  1168.               mov ah,8                      ;get character
  1169.               xor bh,bh
  1170.               int 10h
  1171.               mov ah,9                      ;write character and attribute
  1172.               mov bl,attribute
  1173.               mov cx,1
  1174.               int 10h
  1175.               ret
  1176. SetAttribute  endp
  1177.  
  1178. ;-----------------------------------------------------------------------------
  1179. ;SaveLine saves the contents of the menu line.
  1180. ;-----------------------------------------------------------------------------
  1181. cursor_mode   dw ?                          ;cursor mode
  1182. cursor_pos    dw ?                          ;cursor position
  1183.  
  1184. SaveLine      proc near
  1185.               mov ah,3                      ;get cursor position and shape
  1186.               xor bh,bh
  1187.               int 10h
  1188.               mov cursor_mode,cx            ;save cursor parameters
  1189.               mov cursor_pos,dx
  1190.               mov ah,1                      ;hide the cursor
  1191.               mov ch,20h
  1192.               int 10h
  1193.               mov dx,1800h                  ;set starting cursor position
  1194.               mov di,offset data_buffer     ;point DI to save buffer
  1195.               mov cx,lcolumns
  1196. sr1:          mov ah,2                      ;position the cursor
  1197.               int 10h
  1198.               mov ah,8                      ;read character and attribute
  1199.               int 10h
  1200.               stosw                         ;store them
  1201.               inc dl                        ;advance cursor to next column
  1202.               loop sr1                      ;loop until line is done
  1203.               ret
  1204. SaveLine      endp
  1205.  
  1206. ;-----------------------------------------------------------------------------
  1207. ;RestoreLine restores the contents of the previously saved menu line.
  1208. ;-----------------------------------------------------------------------------
  1209. RestoreLine   proc near
  1210.               mov ah,1                      ;hide the cursor
  1211.               mov ch,20h
  1212.               int 10h
  1213.               xor bh,bh
  1214.               mov si,offset data_buffer     ;point SI to saved char/attr's
  1215.               mov cx,lcolumns
  1216.               mov dx,1800h                  ;initialize cursor position
  1217. rr1:          push cx
  1218.               mov ah,2                      ;position the cursor
  1219.               int 10h
  1220.               lodsw                         ;get character and attribute
  1221.               mov bl,ah                     ;transfer attribute to BL
  1222.               mov ah,9                      ;write character and attribute
  1223.               mov cx,1
  1224.               int 10h
  1225.               inc dl                        ;advance cursor to next column
  1226.               pop cx
  1227.               loop rr1                      ;loop until line is done
  1228.               mov ah,2                      ;restore cursor position and shape
  1229.               mov dx,cursor_pos
  1230.               int 10h
  1231.               mov ah,1
  1232.               mov cx,cursor_mode
  1233.               int 10h
  1234.               ret
  1235. RestoreLine   endp
  1236.  
  1237. ;-----------------------------------------------------------------------------
  1238. ;GetEnv returns a value reflecting what lies on all four sides of the cursor.
  1239. ;Entry:  DH,DL - cursor position       | Exit:  BOXID - neighbor code
  1240. ;-----------------------------------------------------------------------------
  1241. c_pos         label word
  1242. c_col         db ?                          ;cursor column
  1243. c_row         db ?                          ;cursor row
  1244.  
  1245. GetEnv        proc near
  1246.               mov c_pos,dx                  ;save cursor position
  1247.               call VideoAddr                ;calculate video address
  1248.               mov dx,crtc_addr
  1249.               add dx,6
  1250.               push ds                       ;save DS
  1251.               mov ds,video_segment          ;point DS to video buffer
  1252.               assume ds:nothing
  1253. ;
  1254. ;Determine if what lies on the left affects the current cell.
  1255. ;
  1256.               sub si,2                      ;address cell on left
  1257.               cmp c_col,0                   ;at left edge of screen?
  1258.               je check2                     ;yes, then skip test
  1259.               test boxid,12                 ;branch if BOXID is biased
  1260.               jnz check2
  1261.               mov ah,4
  1262.               call MakeCode                 ;generate BOXID code
  1263. ;
  1264. ;Then do the same for the right side.
  1265. ;
  1266. check2:       add si,4
  1267.               mov al,columns
  1268.               cmp c_col,al
  1269.               je check4
  1270.               test boxid,192
  1271.               jnz check4
  1272.               mov ah,64
  1273.               call MakeCode
  1274. ;
  1275. ;Check the character above the current cell.
  1276. ;
  1277. check4:       sub si,linelength
  1278.               sub si,2
  1279.               cmp c_row,0
  1280.               je check6
  1281.               test boxid,48
  1282.               jnz check6
  1283.               mov ah,16
  1284.               call MakeCode
  1285. ;
  1286. ;Finish up by checking the character below.
  1287. ;
  1288. check6:       add si,linelength
  1289.               add si,linelength
  1290.               cmp c_row,24
  1291.               je check8
  1292.               test boxid,3
  1293.               jnz check8
  1294.               mov ah,1
  1295.               call MakeCode
  1296. check8:       pop ds                        ;restore DS
  1297.               assume ds:code
  1298.               mov dx,c_pos                  ;restore DX
  1299.               ret                           ;and exit
  1300. GetEnv        endp
  1301.  
  1302. ;-----------------------------------------------------------------------------
  1303. ;MakeCode modifies BOXID to reflect the character addressed by DS:SI.
  1304. ;Entry:  DS:SI - character
  1305. ;        AH    - test value
  1306. ;        DX    - video status register
  1307. ;-----------------------------------------------------------------------------
  1308. MakeCode      proc near
  1309.               assume ds:nothing
  1310.               call GetChar                  ;retrieve character
  1311.               cmp al,179                    ;exit if not a graphics character
  1312.               jb make_exit
  1313.               cmp al,218
  1314.               ja make_exit
  1315.               sub al,179                    ;check for single extension
  1316.               mov bx,offset gr_table
  1317.               xlat gr_table
  1318.               test al,ah
  1319.               jz make1
  1320.               or boxid,ah
  1321.               jmp short make_exit
  1322. make1:        shl ah,1                      ;check for double extension
  1323.               test al,ah
  1324.               jz make_exit
  1325.               or boxid,ah
  1326. make_exit:    ret
  1327. MakeCode      endp
  1328.  
  1329. ;-----------------------------------------------------------------------------
  1330. ;GetChar returns the character addressed by DS:SI in AL.
  1331. ;Entry:  DS:SI - character cell        | Exit:  AL - character code
  1332. ;        DX    - video status register |
  1333. ;-----------------------------------------------------------------------------
  1334. GetChar       proc near
  1335.               assume ds:nothing
  1336.               in al,dx                      ;wait for horizontal scan
  1337.               test al,1
  1338.               jnz GetChar
  1339.               cli                           ;interrupts off
  1340. wait1:        in al,dx                      ;wait for next retrace
  1341.               test al,1
  1342.               jz wait1
  1343.               mov al,[si]                   ;get the character
  1344.               sti                           ;interrupts on
  1345.               ret
  1346. GetChar       endp
  1347.  
  1348.               assume ds:code
  1349.  
  1350. ;-----------------------------------------------------------------------------
  1351. ;MenuLine opens a menu line at the bottom of the screen.
  1352. ;Entry:  DS:SI - text of menu line
  1353. ;-----------------------------------------------------------------------------
  1354. MenuLine      proc near
  1355.               push si                       ;save string address
  1356.               call SaveLine                 ;save current line contents
  1357.               mov ah,2                      ;position cursor on menu line
  1358.               xor bh,bh
  1359.               mov dx,1800h
  1360.               int 10h
  1361.               mov ax,0920h                  ;clear menu line
  1362.               mov bl,menu_attr
  1363.               mov cx,lcolumns
  1364.               int 10h
  1365.               pop si                        ;retrieve string address
  1366.               call WriteLine                ;display text
  1367.               ret
  1368. MenuLine      endp
  1369.  
  1370. ;-----------------------------------------------------------------------------
  1371. ;WriteLine displays a line of ASCIIZ text.
  1372. ;Entry:  DS:SI - text string
  1373. ;        DH,DL - cursor row and column
  1374. ;-----------------------------------------------------------------------------
  1375. WriteLine     proc near
  1376.               mov ah,2                      ;position the cursor
  1377.               xor bh,bh
  1378.               int 10h
  1379. write1:       lodsb                         ;get a character
  1380.               or al,al                      ;exit if it's zero
  1381.               je write2
  1382.               mov ah,10                     ;write it
  1383.               mov cx,1
  1384.               int 10h
  1385.               mov ah,2
  1386.               inc dl
  1387.               int 10h
  1388.               jmp write1                    ;loop back for more
  1389. write2:       ret
  1390. WriteLine     endp
  1391.  
  1392. ;-----------------------------------------------------------------------------
  1393. ;ReadString reads a string of text from the keyboard.
  1394. ;Entry:  CL    - maximum length
  1395. ;        DH,DL - cursor position
  1396. ;        DS:SI - default string
  1397. ;        ES:DI - input buffer
  1398. ;-----------------------------------------------------------------------------
  1399. maxlen        db ?                          ;maximum accepted length
  1400.  
  1401. ReadString    proc near
  1402.               mov maxlen,cl                 ;store max length
  1403.               xor cl,cl                     ;initialize counter
  1404.               xor bh,bh
  1405. rs1:          lodsb                         ;input default string
  1406.               or al,al                      ;end of string?
  1407.               je rs2                        ;yes, then exit loop
  1408.               inc di                        ;advance buffer pointer
  1409.               inc cl                        ;increment count
  1410.               mov ah,14                     ;print the character
  1411.               int 10h
  1412.               jmp short rs1                 ;loop until zero byte is reached
  1413. rs2:          call ReadKey                  ;read the keyboard
  1414.               cmp al,8                      ;BACKSPACE key?
  1415.               jne rs3
  1416.               or cl,cl                      ;at beginning of line?
  1417.               je rs2                        ;yes, then ignore it
  1418.               mov ah,14                     ;move cursor back one space
  1419.               int 10h
  1420.               push cx                       ;delete the last character
  1421.               mov ax,0A20h
  1422.               mov cx,1
  1423.               int 10h
  1424.               pop cx
  1425.               dec cl                        ;decrement count and pointer
  1426.               dec di
  1427.               jmp short rs2                 ;return for more
  1428. rs3:          cmp al,13                     ;ENTER key?
  1429.               jne rs4                       ;no, then branch
  1430.               xor al,al                     ;mark end of string
  1431.               stosb
  1432.               ret                           ;done
  1433. rs4:          cmp al,27                     ;ESC key?
  1434.               jne rs5                       ;no, then branch
  1435.               xor cl,cl                     ;zero count
  1436.               mov al,cl                     ;place delimiter
  1437.               stosb
  1438.               ret
  1439. rs5:          cmp al,32                     ;ASCII code less than 32?
  1440.               jb rs2                        ;yes, then ignore it
  1441.               cmp cl,maxlen                 ;room for more?
  1442.               je rs2                        ;no, then ignore keypress
  1443.               stosb                         ;buffer the character
  1444.               inc cl                        ;increment count
  1445.               mov ah,14                     ;print the character
  1446.               int 10h
  1447.               jmp short rs2                 ;return for more
  1448. ReadString    endp
  1449.  
  1450. ;-----------------------------------------------------------------------------
  1451. ;BACKSPACE backspaces over the last character.
  1452. ;Entry:  DH,DL - cursor row and column
  1453. ;-----------------------------------------------------------------------------
  1454. backspace     proc near
  1455.               mov ah,2                      ;move cursor back one column
  1456.               dec dl
  1457.               xor bh,bh
  1458.               int 10h
  1459.               cmp insert_flag,0             ;is insert mode active?
  1460.               je bs_exit                    ;no, then we're done
  1461.               push dx                       ;save cursor position
  1462.               call delete                   ;draw in everything to the right
  1463.               pop dx                        ;retrieve position
  1464. bs_exit:      ret
  1465. backspace     endp
  1466.  
  1467. ;-----------------------------------------------------------------------------
  1468. ;DELETE shifts everything right of the cursor one cell left.
  1469. ;Entry:  DH,DL - cursor row and column
  1470. ;-----------------------------------------------------------------------------
  1471. delete        proc near
  1472.               mov cl,columns                ;calculate number of shifts
  1473.               sub cl,dl
  1474.               xor ch,ch
  1475.               jcxz nodelete                 ;branch if there are none
  1476.               call VideoAddr                ;calculate video address
  1477.               mov di,si
  1478.               add si,2
  1479.               push ds                       ;save DS and ES
  1480.               push es
  1481.               assume ds:nothing,es:nothing
  1482.               mov ds,video_segment
  1483.               mov es,video_segment
  1484.               mov dx,crtc_addr              ;get CRT Controller address
  1485.               add dx,6                      ;address status register
  1486. rwait:        in al,dx                      ;wait for vertical retrace
  1487.               test al,8
  1488.               jz rwait
  1489.               cmp write_mode,0              ;delete text and attribute?
  1490.               jne delete_all                ;yes, then branch
  1491. del_loop:     movsb                         ;delete text only
  1492.               inc si
  1493.               inc di
  1494.               loop del_loop
  1495.               jmp short finish
  1496. delete_all:   rep movsw                     ;shift characters and attributes
  1497. finish:       mov byte ptr es:[di],32       ;blank final cell
  1498.               pop es                        ;restore DS and ES
  1499.               pop ds
  1500.               assume ds:code,es:code
  1501.               ret
  1502. nodelete:     mov ax,0A20h                  ;blank character under cursor
  1503.               xor bh,bh
  1504.               mov cx,1
  1505.               int 10h
  1506.               ret
  1507. delete        endp
  1508.  
  1509. data_buffer   label byte                    ;buffer for menu line
  1510.  
  1511. code          ends
  1512.               end begin
  1513.